home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 42
/
Amiga Format AFCD42 (Issue 126, Aug 1999).iso
/
-serious-
/
comms
/
other
/
slrn
/
slrn_src
/
src
/
group.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-05-14
|
63KB
|
2,622 lines
/* -*- mode: C; mode: fold -*- */
/* Copyright (c) 1998 John E. Davis (davis@space.mit.edu)
*
* This file is part of slrn.
*
* Slrn is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* Slrn is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with Slrn; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include "slrnfeat.h"
/*{{{ Include files */
#include <stdio.h>
#include <string.h>
#include <time.h>
#ifndef VMS
# include <sys/types.h>
# include <sys/stat.h>
#else
# include "vms.h"
#endif
#include <signal.h>
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <slang.h>
#include "jdmacros.h"
#include "slrn.h"
#include "group.h"
#include "art.h"
#include "misc.h"
#include "post.h"
#include "server.h"
#include "hash.h"
#include "score.h"
#include "menu.h"
#include "util.h"
#include "startup.h"
#include "slrndir.h"
/*}}}*/
/*{{{ Global Variables */
int Slrn_Query_Group_Cutoff = 100;
int Slrn_Groups_Dirty; /* greater than 0 if need to write newsrc */
int Slrn_List_Active_File = 0;
int Slrn_Use_Xgtitle = 0;
int Slrn_Write_Newsrc_Flags = 0; /* if 1, do not save unsubscribed
* if 2, do not save new unsubscribed.
*/
int Slrn_Display_Cursor_Bar;
int Slrn_Group_Description_Column = 40;/* column where group descr start */
char *Slrn_Group_Help_Line;
Slrn_Group_Type *Slrn_Group_Current_Group;
static SLscroll_Window_Type Group_Window;
static Slrn_Group_Type *Groups;
int Slrn_Group_Display_Descriptions = 1;
int Slrn_No_Backups = 0;
int Slrn_Prompt_Next_Group = 1;
int Slrn_Unsubscribe_New_Groups = 0;
SLKeyMap_List_Type *Slrn_Group_Keymap;
int *Slrn_Prefix_Arg_Ptr;
/*}}}*/
/*{{{ Static Variables */
#define GROUP_HASH_TABLE_SIZE 1250
static Slrn_Group_Type *Group_Hash_Table [GROUP_HASH_TABLE_SIZE];
static unsigned int Last_Cursor_Row;
static int Groups_Hidden; /* if true, hide groups with no arts */
typedef struct Unsubscribed_Slrn_Group_Type
{
char name[MAX_GROUP_NAME_LEN + 1];
struct Unsubscribed_Slrn_Group_Type *next;
}
Unsubscribed_Slrn_Group_Type;
static Unsubscribed_Slrn_Group_Type *Unsubscribed_Groups;
/*}}}*/
/*{{{ Forward Function Declarations */
static void group_update_screen (void);
static void group_quick_help (void);
static void save_newsrc_cmd (void);
/*}}}*/
/*{{{ Functions that deal with Group Range */
/* Note: This routine is NOT very robust. It assumes that this function
* is called in an ordered way such that the implied range is always increasing.
* This is why the range is re-built in art.c:update_ranges. Yes, it is ugly.
* See also slrn_group_mark_article_as_read for something more random.
*/
void slrn_add_group_ranges (Slrn_Group_Type *g, int min, int max) /*{{{*/
{
Slrn_Range_Type *r, *next;
int unread;
if ((max < min) || (g == NULL)) return;
/* The first one is range of articles on server so expand max to cover
* the range of articles nolonger available.
*/
next = &g->range;
if (max < next->min)
{
/* If we have already expanded the range up to range currently available
* at server and we are now trying to add another range below available
* range, do not bother.
*/
if (next->next != NULL) return;
max = next->min - 1;
}
/* Count number unread */
unread = next->max;
while (next->next != NULL)
{
next = next->next;
unread -= next->max - next->min + 1;
}
/* check to see if a merge is possible */
if ((min <= next->max + 1)
&& (next != &g->range))
{
next->max = max;
}
else
{
r = (Slrn_Range_Type *) slrn_safe_malloc (sizeof(Slrn_Range_Type));
r->next = next->next;
next->next = r;
r->prev = next;
r->min = min;
r->max = max;
/* For this case, min should be 1 */
if (next == &g->range)
{
min = r->min = 1;
}
}
unread -= max - min + 1;
if (unread < 0) unread = 0;
g->unread = unread;
Slrn_Groups_Dirty = 1;
}
/*}}}*/
static void group_mark_article_as_read (Slrn_Group_Type *g, long num) /*{{{*/
{
Slrn_Range_Type *r, *r1, *newr;
r1 = &g->range;
if (r1->max < num) /* not at server yet so update our data */
{
r1->max = num;
g->unread += 1;
}
r = r1->next;
while (r != NULL)
{
/* Already read */
if ((num <= r->max) && (num >= r->min)) return;
if (num < r->min) break;
r1 = r;
r = r->next;
}
if (g->unread > 0) g->unread -= 1;
Slrn_Groups_Dirty = 1;
if ((r != NULL) && (r->min == num + 1))
{
r->min = num;
return;
}
if ((r1->max + 1 == num) && (r1 != &g->range))
{
r1->max = num;
return;
}
newr = (Slrn_Range_Type *) slrn_safe_malloc (sizeof (Slrn_Range_Type));
newr->min = newr->max = num;
newr->next = r;
if (r != NULL) r->prev = newr;
newr->prev = r1;
r1->next = newr;
}
/*}}}*/
void slrn_mark_article_as_read (char *group, long num) /*{{{*/
{
Slrn_Group_Type *g;
unsigned long hash;
if (group == NULL)
{
group_mark_article_as_read (Slrn_Group_Current_Group, num);
return;
}
hash = slrn_compute_hash ((unsigned char *) group,
(unsigned char *) group + strlen (group));
g = Group_Hash_Table[hash % GROUP_HASH_TABLE_SIZE];
while (g != NULL)
{
if ((g->hash == hash) && !strcmp (group, g->name))
{
/* If it looks like we have read this group, mark it read. */
if (((g->flags & GROUP_UNSUBSCRIBED) == 0)
|| (g->range.next != NULL))
group_mark_article_as_read (g, num);
break;
}
g = g->hash_next;
}
}
/*}}}*/
static int group_sync_group_with_server (Slrn_Group_Type *g, int *minp, int *maxp) /*{{{*/
{
int min, max, n, max_available;
char *group;
Slrn_Range_Type *r;
int status;
if (g == NULL) return -1;
group = g->name;
slrn_message_now ("Selecting %s ...", group);
status = Slrn_Server_Obj->sv_select_group (group, minp, maxp);
if (status == -1)
return -1;
if (status != OK_GROUP)
{
g->flags |= GROUP_UNSUBSCRIBED;
slrn_error ("This group appears to be bogus.");
return -1;
}
min = *minp;
max = *maxp;
if (max == 0)
{
int nmax, nmin;
nmax = g->range.max;
nmin = g->range.min;
/* Server database inconsistent. */
for (n = nmin; n <= nmax; n++)
group_mark_article_as_read (g, n);
/* g->unread = 0; */
slrn_message ("No articles to read.");
Slrn_Full_Screen_Update = 1;
Slrn_Groups_Dirty = 1;
return -1;
}
g->range.min = min;
if (max < g->range.max)
{
/* There is only one way for this to happen that I am aware of:
* an article has been cancelled-- update the ranges.
*/
int nmax = g->range.max;
for (n = max + 1; n <= nmax; n++)
group_mark_article_as_read (g, n);
}
else g->range.max = max;
/* In case more articles arrived at the server between the time that
* slrn was first started and when the server was just queried, update
* the ranges of read/unread articles.
*/
max_available = g->range.max - g->range.min + 1;
r = &g->range;
if (r->next != NULL)
{
#if 0
/* stesch@parsec.rhein-neckar.de (Stefan Scholl) suggests moving this
* below to avoid posibility of n < 0.
*/
if (r->next->min <= r->min)
r->next->min = 1;
#endif
n = r->max;
while (r->next != NULL)
{
r = r->next;
n -= r->max - r->min + 1;
}
if (n < 0) n = 0;
if (n > max_available) n = max_available;
g->unread = n;
#if 1
r = &g->range;
if (r->next->min <= r->min)
r->next->min = 1;
#endif
}
return 0;
}
/*}}}*/
static void free_group_ranges (Slrn_G